package fuck.handler;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import fuck.ActionContext;
import fuck.bean.Datas;
import fuck.loader.ExcelLoader;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ui.console.MessageConsoleStream;
import org.osgi.framework.Bundle;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class CreateJavaFilesHandler implements Handler {
	private Configuration cfg;
	private ActionContext context;

	public CreateJavaFilesHandler(ActionContext context) {
		this.context = context;
		try {
			this.cfg = new Configuration();
			Bundle bundle = Platform.getBundle("fuck");
			URL url = FileLocator.find(bundle, new Path("./resource/java_ftl/"), null);
			url = FileLocator.toFileURL(url);
			java.io.File path = new java.io.File(url.getPath());

			this.cfg.setDirectoryForTemplateLoading(path);
			this.cfg.setObjectWrapper(new DefaultObjectWrapper());
		} catch (IOException e) {
			context.getMcs().println(e.getMessage());
		}
	}

	public void action(Object[] parameters) {
		this.context.getMcs().println("parameters = " + parameters);
		if ((this.context.getSelection() != null) && ((this.context.getSelection() instanceof StructuredSelection)) && (!this.context.getSelection().isEmpty())) {
			boolean overwrite = false;
			boolean cancel = false;
			Iterator it = ((StructuredSelection) this.context.getSelection()).iterator();
			label2072: while (it.hasNext()) {
				Object obj = it.next();
				if ((obj instanceof org.eclipse.core.internal.resources.File)) {
					org.eclipse.core.internal.resources.File file = (org.eclipse.core.internal.resources.File) obj;
					ExcelLoader loader = new ExcelLoader();
					ArrayList infos = loader.load(this.context, file.getLocation().toString(), false);
					try {
						IProject project = file.getWorkspace().getRoot().getProject(this.context.getConfig().getJavaProject());

						IJavaProject javaProject = JavaCore.create(project);

						//TODO maven这里需要修改
						IFolder srcFolder = javaProject.getProject().getFolder("src");
						
						if (!srcFolder.exists())
							srcFolder.create(true, true, null);

						Iterator iter = infos.iterator();//遍历excel 的sheet
						do {
							Datas dataInfos = (Datas) iter.next();

							String name = dataInfos.getName().toUpperCase().charAt(0) + dataInfos.getName().substring(1);

							if ((((Boolean) parameters[0]).booleanValue()) && (!cancel)) {
								Template temp = this.cfg.getTemplate("Bean.ftl");

								//eclipse创建代码
								IPackageFragmentRoot packageFragmentRoot = javaProject.findPackageFragmentRoot(srcFolder.getFullPath());

								IPackageFragment packageFragment = packageFragmentRoot.getPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".bean");

								if (!packageFragment.exists())
									packageFragmentRoot.createPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".bean", true, null);

								ICompilationUnit beanFile = packageFragment.getCompilationUnit(name + "Bean.java");
								if (beanFile.exists()) {
									if (!overwrite) {
										MessageDialog dialog = new MessageDialog(this.context.getShell(), "Question", null, beanFile.getPath().lastSegment()
												+ " exits.Do you wish to overwrite?", 3, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL,
												IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
										dialog.open();
										int result = dialog.getReturnCode();

										if (result == 0) {
											beanFile.delete(false, new NullProgressMonitor());
											createBean(temp, packageFragment, dataInfos);
										} else if (result == 1) {
											overwrite = true;
											beanFile.delete(false, new NullProgressMonitor());
											createBean(temp, packageFragment, dataInfos);
										} else {
											if (result == 2) {
												break label2072;
											}
											if (result == 3) {
												cancel = true;
												break;
											}
										}
									} else {
										beanFile.delete(false, new NullProgressMonitor());
										createBean(temp, packageFragment, dataInfos);
									}
								} else {
									createBean(temp, packageFragment, dataInfos);
								}

							}

							if ((((Boolean) parameters[1]).booleanValue()) && (!cancel)) {
								//创建DAO的时候创建mapper
								Template temp = this.cfg.getTemplate("Dao.ftl");

								IPackageFragmentRoot packageFragmentRoot = javaProject.findPackageFragmentRoot(srcFolder.getFullPath());

								IPackageFragment packageFragment = packageFragmentRoot.getPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".dao");

								if (!packageFragment.exists())
									packageFragmentRoot.createPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".dao", true, null);

								ICompilationUnit beanFile = packageFragment.getCompilationUnit(name + "Dao.java");
								if (beanFile.exists()) {
									if (!overwrite) {
										MessageDialog dialog = new MessageDialog(this.context.getShell(), "Question", null, beanFile.getPath().lastSegment()
												+ " exits.Do you wish to overwrite?", 3, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL,
												IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
										dialog.open();
										int result = dialog.getReturnCode();

										if (result == 0) {
											beanFile.delete(false, new NullProgressMonitor());
											createDao(temp, packageFragment, dataInfos);
										} else if (result == 1) {
											overwrite = true;
											beanFile.delete(false, new NullProgressMonitor());
											createDao(temp, packageFragment, dataInfos);
										} else {
											if (result == 2) {
												break label2072;
											}
											if (result == 3) {
												cancel = true;
												break;
											}
										}
									} else {
										beanFile.delete(false, new NullProgressMonitor());
										createDao(temp, packageFragment, dataInfos);
									}
								} else {
									createDao(temp, packageFragment, dataInfos);
								}

								temp = this.cfg.getTemplate("DaoXML.ftl");

								packageFragmentRoot = javaProject.findPackageFragmentRoot(srcFolder.getFullPath());

								packageFragment = packageFragmentRoot.getPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".sqlmap");

								if (!packageFragment.exists())
									packageFragmentRoot.createPackageFragment(this.context.getConfig().getJavaExcelPackage() + ".sqlmap", true, null);

								IFolder xmlFolder = srcFolder.getFolder((this.context.getConfig().getJavaExcelPackage() + ".sqlmap").replaceAll("\\.", "\\\\"));

								IFile xmlFile = xmlFolder.getFile(dataInfos.getName() + ".xml");
								if (xmlFile.exists()) {
									if (!overwrite) {
										MessageDialog dialog = new MessageDialog(this.context.getShell(), "Question", null, xmlFile.getName() + " exits.Do you wish to overwrite?",
												3, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL, IDialogConstants.NO_LABEL,
														IDialogConstants.CANCEL_LABEL }, 0);
										dialog.open();
										int result = dialog.getReturnCode();

										if (result == 0) {
											xmlFile.delete(false, new NullProgressMonitor());
											createXML(temp, xmlFolder, dataInfos);
										} else if (result == 1) {
											overwrite = true;
											xmlFile.delete(false, new NullProgressMonitor());
											createXML(temp, xmlFolder, dataInfos);
										} else {
											if (result == 2) {
												break label2072;
											}
											if (result == 3) {
												cancel = true;
												break;
											}
										}
									} else {
										xmlFile.delete(false, new NullProgressMonitor());
										createXML(temp, xmlFolder, dataInfos);
									}
								} else {
									createXML(temp, xmlFolder, dataInfos);
								}

							}

							if ((((Boolean) parameters[2]).booleanValue()) && (!cancel)) {
								Template temp = this.cfg.getTemplate("Container.ftl");

								IPackageFragmentRoot packageFragmentRoot = javaProject.findPackageFragmentRoot(srcFolder.getFullPath());

								IPackageFragment packageFragment = packageFragmentRoot.getPackageFragment("com.game.data.container");

								if (!packageFragment.exists())
									packageFragmentRoot.createPackageFragment("com.game.data.container", true, null);

								ICompilationUnit beanFile = packageFragment.getCompilationUnit(name + "Container.java");
								if (beanFile.exists()) {
									if (!overwrite) {
										MessageDialog dialog = new MessageDialog(this.context.getShell(), "Question", null, beanFile.getPath().lastSegment()
												+ " exits.Do you wish to overwrite?", 3, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL,
												IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
										dialog.open();
										int result = dialog.getReturnCode();

										if (result == 0) {
											beanFile.delete(false, new NullProgressMonitor());
											createContainer(temp, packageFragment, dataInfos);
										} else if (result == 1) {
											overwrite = true;
											beanFile.delete(false, new NullProgressMonitor());
											createContainer(temp, packageFragment, dataInfos);
										} else {
											if (result == 2) {
												break label2072;
											}
											if (result == 3) {
												cancel = true;
												break;
											}
										}
									} else {
										beanFile.delete(false, new NullProgressMonitor());
										createContainer(temp, packageFragment, dataInfos);
									}
								} else {
									createContainer(temp, packageFragment, dataInfos);
								}

							}

							IFile configFile = srcFolder.getFile("data-config.xml");
							if (!configFile.exists()) {
								org.eclipse.core.internal.resources.File selection = (org.eclipse.core.internal.resources.File) ((StructuredSelection) this.context.getSelection())
										.getFirstElement();
								IFile dbConfigFile = selection.getProject().getFile(this.context.getConfig().getDbConfig());
								configFile.create(dbConfigFile.getContents(), true, new NullProgressMonitor());
								dbConfigFile.getContents().close();
							}
							
							//向data-config中添加mapper
							registerXML(configFile, dataInfos);

							IPackageFragmentRoot packageFragmentRoot = javaProject.findPackageFragmentRoot(srcFolder.getFullPath());

							IPackageFragment packageFragment = packageFragmentRoot.getPackageFragment(getPath(this.context.getConfig().getJavaExcelPool()));

							if (!packageFragment.exists())
								packageFragmentRoot.createPackageFragment(getPath(this.context.getConfig().getJavaExcelPool()), true, null);

							Template temp = this.cfg.getTemplate("DataManager.ftl");

							ICompilationUnit beanFile = packageFragment.getCompilationUnit(lastSegment(this.context.getConfig().getJavaExcelPool()) + ".java");
							if (beanFile.exists()) {
								beanFile.delete(true, new NullProgressMonitor());
							}
							createIncludeFile(temp, packageFragment, configFile, this.context);

							if (!iter.hasNext())
								break;
						} while (!cancel);
					} catch (CoreException e) {
						this.context.getMcs().println(e.getMessage());
					} catch (UnsupportedEncodingException e) {
						this.context.getMcs().println(e.getMessage());
					} catch (IOException e) {
						this.context.getMcs().println(e.getMessage());
					}
				}
			}
		}
	}

	private void createXML(Template temp, IFolder xmlFolder, Datas dataInfos) {
		try {
			HashMap root = new HashMap();
			String name = dataInfos.getName().toUpperCase().charAt(0) + dataInfos.getName().substring(1);

			root.put("beanClass", this.context.getConfig().getJavaExcelPackage() + ".bean." + name + "Bean");
			root.put("name", dataInfos.getName());
			root.put("fields", dataInfos.getFields());

			IFile xmlFile = xmlFolder.getFile(dataInfos.getName() + ".xml");

			ByteArrayOutputStream outStream = new ByteArrayOutputStream();
			Writer out = new OutputStreamWriter(outStream);
			temp.process(root, out);

			ByteArrayInputStream inputStream = new ByteArrayInputStream(outStream.toString("UTF-8").getBytes("UTF-8"));
			xmlFile.create(inputStream, true, new NullProgressMonitor());

			out.close();
			outStream.close();
			inputStream.close();
		} catch (IOException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (CoreException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (TemplateException e) {
			this.context.getMcs().println(e.getMessage());
		}
	}

	private void createBean(Template temp, IPackageFragment packageFragment, Datas dataInfos) {
		try {
			HashMap root = new HashMap();
			String name = dataInfos.getName().toUpperCase().charAt(0) + dataInfos.getName().substring(1);

			root.put("package", this.context.getConfig().getJavaExcelPackage() + ".bean");
			root.put("className", name + "Bean");
			root.put("explain", name + " Bean");
			root.put("fields", dataInfos.getFields());

			Writer out = new StringWriter();
			temp.process(root, out);

			packageFragment.createCompilationUnit(name + "Bean.java", out.toString(), false, new NullProgressMonitor());

			out.close();
		} catch (IOException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (TemplateException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (JavaModelException e) {
			this.context.getMcs().println(e.getMessage());
		}
	}

	private void createDao(Template temp, IPackageFragment packageFragment, Datas dataInfos) {
		try {
			HashMap root = new HashMap();
			String name = dataInfos.getName().toUpperCase().charAt(0) + dataInfos.getName().substring(1);

			root.put("package", this.context.getConfig().getJavaExcelPackage() + ".dao");
			root.put("basePackage", this.context.getConfig().getJavaExcelPackage());
			root.put("className", name + "Dao");
			root.put("explain", name + " Dao");
			root.put("beanClass", name + "Bean");
			root.put("xmlName", dataInfos.getName());
			List imports = new ArrayList();
			imports.add(this.context.getConfig().getJavaExcelPackage() + ".bean." + name + "Bean");
			root.put("imports", imports);

			Writer out = new StringWriter();
			temp.process(root, out);

			packageFragment.createCompilationUnit(name + "Dao.java", out.toString(), false, new NullProgressMonitor());

			out.close();
		} catch (IOException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (TemplateException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (JavaModelException e) {
			this.context.getMcs().println(e.getMessage());
		}
	}

	private void createContainer(Template temp, IPackageFragment packageFragment, Datas dataInfos) {
		try {
			HashMap root = new HashMap();
			String name = dataInfos.getName().toUpperCase().charAt(0) + dataInfos.getName().substring(1);

			root.put("package", this.context.getConfig().getJavaExcelPackage() + ".container");
			root.put("className", name + "Container");
			root.put("explain", name + "数据容器");
			List imports = new ArrayList();
			imports.add(this.context.getConfig().getJavaExcelPackage() + ".bean." + name + "Bean");
			imports.add(this.context.getConfig().getJavaExcelPackage() + ".dao." + name + "Dao");
			root.put("beanClass", name + "Bean");
			root.put("daoClass", name + "Dao");
			root.put("imports", imports);
			root.put("keyName", dataInfos.getKey().getName());
			root.put("keyClass", dataInfos.getKey().getJavaClassName());

			Writer out = new StringWriter();
			temp.process(root, out);

			packageFragment.createCompilationUnit(name + "Container.java", out.toString(), false, new NullProgressMonitor());

			out.close();
		} catch (IOException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (TemplateException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (JavaModelException e) {
			this.context.getMcs().println(e.getMessage());
		}
	}

	private void registerXML(IFile configFile, Datas dataInfos) {
		try {
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			InputStream is = configFile.getContents();
			Document document = builder.parse(is);

			NodeList list = document.getDocumentElement().getElementsByTagName("mappers");
			if (list.getLength() == 0) {
				Element element = document.createElement("mappers");
				document.getDocumentElement().appendChild(element);
			}
			Node root = document.getDocumentElement().getElementsByTagName("mappers").item(0);

			HashMap mappers = new HashMap();

			NodeList nodes = document.getElementsByTagName("mapper");
			for (int i = 0; i < nodes.getLength(); i++) {
				Node node = nodes.item(i);
				String name = node.getAttributes().getNamedItem("resource").getTextContent();
				mappers.put(name, node);
			}
			is.close();
			String resource = this.context.getConfig().getJavaExcelPackage().replaceAll("\\.", "/") + "/sqlmap/" + dataInfos.getName() + ".xml";
			DocumentType type = document.getDoctype();

			if (!mappers.containsKey(resource)) {
				Element element = document.createElement("mapper");
				element.setAttribute("resource", resource);
				root.appendChild(element);

				TransformerFactory transFactory = TransformerFactory.newInstance();
				Transformer transformer = transFactory.newTransformer();
				transformer.setOutputProperty("encoding", "UTF-8");
				transformer.setOutputProperty("indent", "yes");
				transformer.setOutputProperty("doctype-public", type.getPublicId());
				transformer.setOutputProperty("doctype-system", type.getSystemId());

				DOMSource source = new DOMSource();
				source.setNode(document.getDocumentElement());

				StreamResult result = new StreamResult();

				ByteArrayOutputStream outStream = new ByteArrayOutputStream();
				result.setOutputStream(outStream);

				transformer.transform(source, result);

				ByteArrayInputStream inputStream = new ByteArrayInputStream(outStream.toByteArray());
				configFile.setContents(inputStream, true, true, new NullProgressMonitor());

				outStream.close();
				inputStream.close();
			}
		} catch (FileNotFoundException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (ParserConfigurationException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (IOException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (SAXException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (CoreException e) {
			this.context.getMcs().println(e.getMessage());
		} catch (TransformerException e) {
			this.context.getMcs().println(e.getMessage());
		}
	}

	private void createIncludeFile(Template temp, IPackageFragment packageFragment, IFile configFile, ActionContext context) {
		try {
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			InputStream is = configFile.getContents();
			Document document = builder.parse(is);

			HashMap root = new HashMap();
			root.put("package", getPath(context.getConfig().getJavaExcelPool()));
			root.put("explain", "数据管理");
			root.put("dataPackage", context.getConfig().getJavaExcelPackage());
			List containers = new ArrayList();

			NodeList nodes = document.getElementsByTagName("mapper");
			for (int i = 0; i < nodes.getLength(); i++) {
				Node node = nodes.item(i);
				String name = node.getAttributes().getNamedItem("resource").getTextContent();
				containers.add(name.substring(name.lastIndexOf("/") + 1).replaceAll("\\.xml", ""));
			}
			root.put("containers", containers);
			is.close();

			Writer out = new StringWriter();
			temp.process(root, out);

			packageFragment.createCompilationUnit(lastSegment(context.getConfig().getJavaExcelPool()) + ".java", out.toString(), false, new NullProgressMonitor());

			out.close();
		} catch (FileNotFoundException e) {
			context.getMcs().println(e.getMessage());
		} catch (ParserConfigurationException e) {
			context.getMcs().println(e.getMessage());
		} catch (IOException e) {
			context.getMcs().println(e.getMessage());
		} catch (SAXException e) {
			context.getMcs().println(e.getMessage());
		} catch (CoreException e) {
			context.getMcs().println(e.getMessage());
		} catch (TemplateException e) {
			context.getMcs().println(e.getMessage());
		}
	}

	protected String lastSegment(String fileName) {
		String[] names = fileName.split("\\.");
		return names[(names.length - 1)];
	}

	protected String getPath(String fileName) {
		String[] names = fileName.split("\\.");
		StringBuffer path = new StringBuffer();
		for (int i = 0; i < names.length - 1; i++) {
			path.append("." + names[i]);
		}
		if (path.length() > 0)
			path.deleteCharAt(0);
		return path.toString();
	}
}